home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library / Microsoft Programmer's Library (CD-ROM Database)(125-099-008)(Version 1.1a)(CDRM 162100)(1989).iso / SAMPCODE / OS2SDK11 / TK4 / LINEFRAC / LFDRAW.C < prev    next >
C/C++ Source or Header  |  1989-02-20  |  27KB  |  979 lines

  1. /************************************************************************
  2. *
  3. *   lfdraw.c -- This file contains "line fractal" drawing routines
  4. *
  5. *   Created by Microsoft Corporation, 1989
  6. *
  7. *
  8. *   Background fractal drawing scheme:
  9. *
  10. *    To enable the user to interact with the system during
  11. *    the drawing of a complicated fractal, the fractal is
  12. *    drawn into a bitmap by a background thread.  This thread
  13. *    is started at the first WM_PAINT message received by the
  14. *    application, and never terminates.
  15. *
  16. *    The thread's execution is controlled by a semaphore,
  17. *    lSemRedraw.  The thread is initially blocked
  18. *    by its semaphore.  When something changes in the environ-
  19. *    ment such that the fractal is to be redrawn, or drawn for
  20. *    the first time, the semaphore is cleared and the thread
  21. *    is off and running.  Note that the environment must be
  22. *    set up BEFORE the semaphore is cleared, otherwise the
  23. *    fractal may be partially drawn with old parameters.
  24. *    The thread automatically resets the semaphore, so that
  25. *    as soon as it's done drawing, it has to wait for the signal
  26. *    to start again.
  27. *
  28. *    The fractal is drawn in batches of up to 8196 points per polyline.
  29. *    After each polyline is drawn, the background thread invalidates
  30. *    the main client rectangle to force a WM_PAINT message to be sent.
  31. *    All the paint procedure does is copy the bitmap, whatever
  32. *    it's current state, to the screen.  The user therefore
  33. *    sees bursts of n points at a time as his fractal is drawn.
  34. *
  35. *    The semaphore is controlled, in greater detail, as follows:
  36. *
  37. *        Disable background drawing (set semaphore):
  38. *
  39. *        LfInit
  40. *            Don't let second thread start working until a
  41. *            transform has been defined.
  42. *
  43. *        LineFractalThread
  44. *            Don't start the next one until the user asks for it.
  45. *
  46. *        Enable background drawing (clear semaphore):
  47. *
  48. *        WM_BUTTON1UP
  49. *        WM_BUTTON2UP
  50. *        WM_SIZE & fAutoSizePS
  51. *            The level of recursion or dimensions of bitmap have
  52. *            changed, so redraw the fractal.
  53. *
  54. *        Change of fractal
  55. *        Change of drawing primitive
  56. *        Change of attributes
  57. *            If the corresponding redraw flag is enabled for one
  58. *            of these events, then the semaphore is cleared.
  59. *
  60. *
  61. *     Event                      LineFractalThread
  62. *     -----                      -----------------
  63. *
  64. *    WM_BUTTON1UP                  --------<--------
  65. *    WM_BUTTON2UP                 /           \
  66. *    WM_SIZE & fAutoSizePS            |            |
  67. *    Change of fractal/primitive/attributes    |            |
  68. *       |                    |            |
  69. *       |                    V            |
  70. *       +---------clear----------> +----------------------+        |
  71. *                      |     lSemRedraw         |        |
  72. *       +----------set-----------> +----------------------+        |
  73. *       |                    |            |
  74. *       |                  if semaphore is clear        ^
  75. *    initialization                |            |
  76. * done with current fractal            V            |
  77. *                      +----------------------+        |
  78. *                      |    Draw fractal      |        |
  79. *               WM_PAINT <---- |    into bitmap         |        |
  80. *                      +----------------------+        |
  81. *                        |            |
  82. *                        |            |
  83. *                         \            /
  84. *                          -------->--------
  85. *
  86. ************************************************************************/
  87.  
  88. #define INCL_WIN
  89. #define INCL_GPI
  90. #define INCL_DOSSEMAPHORES
  91. #define INCL_DOSPROCESS
  92.  
  93. #include <os2.h>
  94. #include <mt\math.h>
  95.  
  96. #define INCL_GLOBALS
  97. #define INCL_THREADS
  98. #include "linefrac.h"
  99.  
  100. #define INCL_LFTHREAD
  101. #define INCL_LFDRAW
  102. #include "lffuncs.h"
  103.  
  104.  
  105.  
  106.  
  107. /************************************************************************
  108. *
  109. *   Global Variables
  110. *
  111. ************************************************************************/
  112.  
  113. extern GLOBALDATA global;
  114. extern XFORMDATA  aXform[];
  115.  
  116.  
  117.  
  118.  
  119. /************************************************************************
  120. *
  121. *   LineFractalThread
  122. *
  123. *   Organize the drawing of the fractal.  Runs in an independent
  124. *   thread to accumulate the points of the fractal, then calls
  125. *   LfDraw to draw with the selected primitive onto the surface in
  126. *   batches of a size selected by the user.  If this thread is the
  127. *   top, then all or part of the client rectangle is invalidated
  128. *   after drawing to force a WM_PAINT message.    When the paint message
  129. *   is processed, the image will be copied to the display.
  130. *
  131. *   This function is entered via _beginthread, which takes care of
  132. *   putting the parameter on the stack.
  133. *
  134. ************************************************************************/
  135.  
  136. VOID FAR cdecl
  137. LineFractalThread(pthr)
  138. PTHR pthr;
  139. {
  140.     HAB hab;
  141.     int cFracSegs;
  142.     ULONG cptReq;
  143.     BOOL fCached;
  144.     BOOL fCacheable;
  145.     BOOL fModelXformsValid;
  146.     PLINEFRAC pXform;           /* linked list of fractal segments */
  147.  
  148.  
  149.     hab = WinInitialize(NULL);          /* initialize ring 2 stack for thread */
  150.  
  151.     fModelXformsValid = FALSE;
  152.     fCached          = FALSE;
  153.     fCacheable          = FALSE;
  154.  
  155.     pthr->pptl          = NULL;
  156.     pthr->pmatlf      = NULL;
  157.  
  158.     while (!pthr->fTimeToDie)
  159.     {
  160.     /****************************************************************
  161.     *
  162.     *  Clear the busy flag to indicate we're at the semaphore.
  163.     *  If we happen to be the top thread, then force the pointer
  164.     *  to be what we expect to see (if we didn't do this, it
  165.     *  might stay as an hour glass until the user moves the mouse).
  166.     *
  167.     ****************************************************************/
  168.  
  169.     pthr->fBusy = FALSE;
  170.     if (LfIsThreadTop(pthr))
  171.         if ((global.hptr)[global.usCurPtr])
  172.         WinSetPointer(HWND_DESKTOP,(global.hptr)[global.usCurPtr]);
  173.  
  174.  
  175.     /****************************************************************
  176.     *
  177.     *  Wait for permission to redraw.
  178.     *  See if we're supposed to exit.  If not, clear the suicide
  179.     *  flag, and set the busy flag.  If we're the top thread, then
  180.     *  set the pointer to an hour glass to let the user know we're
  181.     *  working on something.
  182.     *
  183.     ****************************************************************/
  184.  
  185.     DosSemRequest(&pthr->lSemRedraw, -1L);
  186.  
  187.     if (pthr->fTimeToDie)
  188.         goto lfthread_exit;
  189.     pthr->fInterrupted = FALSE;
  190.     pthr->fBusy       = TRUE;
  191.     if (LfIsThreadTop(pthr))
  192.         if (global.hptrWait)
  193.         WinSetPointer(HWND_DESKTOP,global.hptrWait);
  194.  
  195.     /****************************************************************
  196.     *
  197.     *  Check for changes of attributes.  If anything has changed,
  198.     *  this subroutine copies the new stuff over within a critical
  199.     *  section.
  200.     *
  201.     ****************************************************************/
  202.  
  203.     LfUpdateAttrs(pthr);
  204.  
  205.  
  206.     /****************************************************************
  207.     *
  208.     *  Check the buffers for points and model transforms.  If we
  209.     *  don't have them, or the appropriate attributes have changed
  210.     *  such that the ones we have are invalid, allocate for them.
  211.     *
  212.     ****************************************************************/
  213.  
  214.     if ((pthr->pptl == NULL) || (pthr->flMiscAttrs & LFA_CPTMAX))
  215.     {
  216.         if (pthr->pptl != NULL)
  217.         DosFreeSeg(*(((PUSHORT)&pthr->pptl)+1));
  218.         if (DosAllocSeg(pthr->cptMax * sizeof(POINTL),
  219.                ((PUSHORT)&pthr->pptl)+1, 0))
  220.         goto lfthread_exit;
  221.     }
  222.  
  223.     if ((pthr->pmatlf == NULL) || (pthr->flMiscAttrs & LFA_POLYGONSIDES))
  224.     {
  225.         if (pthr->pmatlf != NULL)
  226.         DosFreeSeg(*(((PUSHORT)&pthr->pmatlf)+1));
  227.         if (DosAllocSeg(pthr->usPolygonSides * sizeof(MATRIXLF),
  228.                ((PUSHORT)&pthr->pmatlf)+1, 0))
  229.         goto lfthread_exit;
  230.         fModelXformsValid = FALSE;
  231.     }
  232.  
  233.  
  234.     /****************************************************************
  235.     *
  236.     *  See if we can cache the whole lot of points.  This depends
  237.     *  on the fractal, the size of the point cache, and the level
  238.     *  of recursion.  Note that we must execute this code the first
  239.     *  time through, or fCacheable will be undefined.  We're sure
  240.     *  to come here, though, because threads are initialized with
  241.     *  all attributes "changed".
  242.     *
  243.     ****************************************************************/
  244.  
  245.     if (pthr->flMiscAttrs & (LFA_CPTMAX | LFA_RECURSION | LFA_CURXFORM))
  246.     {
  247.         if (pthr->flMiscAttrs & LFA_CURXFORM)
  248.         {
  249.         PLINEFRAC p;
  250.  
  251.         cFracSegs = 0;
  252.         pXform = aXform[pthr->usCurXform - IDM_SHARKTOOTH].pXform;
  253.         p = pXform;
  254.         while (p != EOLIST)
  255.         {
  256.             ++cFracSegs;
  257.             p = p->next;
  258.         }
  259.         }
  260.  
  261.         cptReq = (ULONG) exp((double)pthr->usRecursion *
  262.                  log((double)cFracSegs));
  263.  
  264.         if ((ULONG)pthr->cptMax > cptReq)
  265.         fCacheable = TRUE;
  266.         else
  267.         fCacheable = FALSE;
  268.  
  269.         fCached = FALSE;
  270.     }
  271.  
  272.  
  273.     /****************************************************************
  274.     *
  275.     *  If the model transforms are invalid, then recompute them.
  276.     *  Check first to see if any attributes have changed that
  277.     *  would invalidate the transforms.
  278.     *
  279.     ****************************************************************/
  280.  
  281.     if (fModelXformsValid)
  282.         if (pthr->flMiscAttrs & (LFA_ROTATION | LFA_POLYGONSIDES |
  283.            LFA_XSCALE | LFA_YSCALE | LFA_XOFF | LFA_YOFF))
  284.         fModelXformsValid = FALSE;
  285.  
  286.     if (!fModelXformsValid)
  287.     {
  288.         LfComputeModelXforms(pthr);
  289.         fModelXformsValid = TRUE;
  290.     }
  291.  
  292.  
  293.     /****************************************************************
  294.     *
  295.     *  Clear the change-of-attributes flags that have been examined
  296.     *  by the time we get here.
  297.     *
  298.     ****************************************************************/
  299.  
  300.     pthr->flMiscAttrs &=
  301.       ~(
  302.          LFA_CPTMAX    | LFA_RECURSION | LFA_POLYGONSIDES | LFA_CURXFORM  |
  303.          LFA_XSCALE    | LFA_YSCALE    | LFA_XOFF          | LFA_YOFF      |
  304.          LFA_ROTATION
  305.        );
  306.  
  307.  
  308.     /****************************************************************
  309.     *
  310.     *  Clear the surface if fClearOnRedraw is enabled.
  311.     *  If the points are cached, then redraw straight from the cache.
  312.     *  Otherwise, anchor the fractal at the left endpoint of the
  313.     *  unit interval, then draw it to the specified depth of recursion.
  314.     *  If we are able to cache all the points, then nothing will have
  315.     *  been drawn when LineFractal returns, so draw the fractal without
  316.     *  flushing the cache.    If we were not able to cache all the
  317.     *  points, and the buffer is not empty, flush the last batch.
  318.     *
  319.     ****************************************************************/
  320.  
  321.     if (pthr->fClearOnRedraw)
  322.         LfClearRect(pthr, NULL);
  323.  
  324.     if (fCached)
  325.         LfDraw(pthr, FALSE);
  326.     else
  327.     {
  328.         pthr->x    =  0.0;
  329.         pthr->y    =  0.0;
  330.  
  331.         pthr->cptl = 0L;
  332.         LfAddPoint(pthr);
  333.  
  334.         LineFractal(pthr, pthr->usRecursion, (double)pthr->cxWCS,
  335.             0.0, FALSE, pXform);
  336.  
  337.         if (!pthr->fInterrupted)
  338.         {
  339.         if (fCacheable)
  340.         {
  341.             LfDraw(pthr, FALSE);
  342.             fCached = TRUE;
  343.         }
  344.         else
  345.         {
  346.             fCached = FALSE;
  347.             if (pthr->cptl > 1L)
  348.             LfDraw(pthr, TRUE);
  349.         }
  350.         }
  351.     }
  352.     }
  353.  
  354.  
  355.     /****************************************************************
  356.     *
  357.     *  Common exit point for thread.  Free up memory allocated
  358.     *  by this thread.
  359.     *
  360.     ****************************************************************/
  361.  
  362. lfthread_exit:
  363.  
  364.     if (pthr->pmatlf != NULL)
  365.     DosFreeSeg(*(((PUSHORT)&pthr->pmatlf)+1));
  366.     if (pthr->pptl != NULL)
  367.     DosFreeSeg(*(((PUSHORT)&pthr->pptl)+1));
  368. }
  369.  
  370.  
  371.  
  372.  
  373. /************************************************************************
  374. *
  375. *   LfUpdateAttrs
  376. *
  377. *   Update any changed attributes from the global attributes.
  378. *
  379. ************************************************************************/
  380.  
  381. VOID
  382. LfUpdateAttrs(pthr)
  383. PTHR pthr;
  384. {
  385.  
  386.     DosEnterCritSec();
  387.     if (pthr->fUpdateAttrs)
  388.     {
  389.     if (global.flLineAttrs     & LFA_LINEALL)
  390.     {
  391.         pthr->lb         = global.lb;
  392.         pthr->flLineAttrs    |= global.flLineAttrs;
  393.         global.flLineAttrs     = 0L;
  394.     }
  395.     if (global.flMarkerAttrs & LFA_MARKALL)
  396.     {
  397.         pthr->mb         = global.mb;
  398.         pthr->flMarkerAttrs |= global.flMarkerAttrs;
  399.         global.flMarkerAttrs = 0L;
  400.     }
  401.     if (global.flAreaAttrs     & LFA_AREAALL)
  402.     {
  403.         pthr->ab         = global.ab;
  404.         pthr->flAreaAttrs    |= global.flAreaAttrs;
  405.         global.flAreaAttrs     = 0L;
  406.     }
  407.     if (global.flImageAttrs  & LFA_IMAGEALL)
  408.     {
  409.         pthr->ib         = global.ib;
  410.         pthr->flImageAttrs    |= global.flImageAttrs;
  411.         global.flImageAttrs  = 0L;
  412.     }
  413.     if (global.flMiscAttrs     & LFA_MISCALL)
  414.     {
  415.         if (global.flMiscAttrs & LFA_CURPRIM)
  416.         pthr->usCurPrim      = global.usCurPrim;
  417.         if (global.flMiscAttrs & LFA_CURXFORM)
  418.         pthr->usCurXform     = global.usCurXform;
  419.         if (global.flMiscAttrs & LFA_RECURSION)
  420.         pthr->usRecursion    = global.usRecursion;
  421.         if (global.flMiscAttrs & LFA_POLYGONSIDES)
  422.         pthr->usPolygonSides = global.usPolygonSides;
  423.         if (global.flMiscAttrs & LFA_CPTMAX)
  424.         pthr->cptMax         = global.cptMax;
  425.         if (global.flMiscAttrs & LFA_XOFF)
  426.         pthr->dblXOff         = global.dblXOff;
  427.         if (global.flMiscAttrs & LFA_YOFF)
  428.         pthr->dblYOff         = global.dblYOff;
  429.         if (global.flMiscAttrs & LFA_XSCALE)
  430.         pthr->dblXScale      = global.dblXScale;
  431.         if (global.flMiscAttrs & LFA_YSCALE)
  432.         pthr->dblYScale      = global.dblYScale;
  433.         if (global.flMiscAttrs & LFA_ROTATION)
  434.         pthr->dblRotation    = global.dblRotation;
  435.         if (global.flMiscAttrs & LFA_CXWCS)
  436.         pthr->cxWCS         = global.cxWCS;
  437.         if (global.flMiscAttrs & LFA_CYWCS)
  438.         pthr->cyWCS         = global.cyWCS;
  439.         pthr->flMiscAttrs  |= global.flMiscAttrs;
  440.         global.flMiscAttrs    = 0L;
  441.     }
  442.  
  443.     pthr->fUpdateAttrs  = FALSE;
  444.     global.fUpdateAttrs = FALSE;
  445.  
  446.     }
  447.     DosExitCritSec();
  448.  
  449.  
  450.     /* Take care of the attribute bundles now. The miscellaneous attributes
  451.      * require more processing, so don't clear their flags yet.
  452.      */
  453.  
  454.     if (pthr->flLineAttrs & LFA_LINEALL)
  455.     {
  456.     GpiSetAttrs(pthr->hps, PRIM_LINE, pthr->flLineAttrs, 0L, &pthr->lb);
  457.     pthr->flLineAttrs = 0L;
  458.     }
  459.     if (pthr->flMarkerAttrs & LFA_MARKALL)
  460.     {
  461.     GpiSetAttrs(pthr->hps, PRIM_MARKER, pthr->flMarkerAttrs, 0L, &pthr->mb);
  462.     pthr->flMarkerAttrs = 0L;
  463.     }
  464.     if (pthr->flAreaAttrs & LFA_AREAALL)
  465.     {
  466.     GpiSetAttrs(pthr->hps, PRIM_AREA, pthr->flAreaAttrs, 0L, &pthr->ab);
  467.     pthr->flAreaAttrs = 0L;
  468.     }
  469.     if (pthr->flImageAttrs)
  470.     {
  471.     GpiSetAttrs(pthr->hps, PRIM_IMAGE, pthr->flImageAttrs, 0L, &pthr->ib);
  472.     pthr->flImageAttrs = 0L;
  473.     }
  474. }
  475.  
  476.  
  477.  
  478.  
  479. /************************************************************************
  480. *
  481. *   LfComputeModelXforms
  482. *
  483. *   Compute the model transform matrices necessary to draw the fractal
  484. *   on each side of the polygonal frame.  The rotation, scaling, and
  485. *   translation are all rolled into one matrix for simplicity.
  486. *
  487. ************************************************************************/
  488.  
  489. VOID
  490. LfComputeModelXforms(pthr)
  491. PTHR pthr;
  492. {
  493.     double dblXScale, dblYScale;
  494.     double dblXOff, dblYOff;
  495.     double dblTheta;
  496.     double dblRotation, dblSinRotation, dblCosRotation;
  497.     double dblSideLen, dblAngleDecr;
  498.     double dblXExtDims, dblYExtDims;
  499.     double dblHalfXDims, dblHalfYDims;
  500.     double dx, dy;
  501.     PMATRIXLF pmatlf;
  502.     int i;
  503.  
  504.  
  505.     dblAngleDecr = TWO_PI / (double)pthr->usPolygonSides;
  506.  
  507.     if (pthr->usPolygonSides == 1)
  508.     {
  509.     dblSideLen   = 1.0;
  510.     dblRotation  = (double) pthr->dblRotation;
  511.     }
  512.     else
  513.     {
  514.     /* C 5.1 incorrectly compiles sin(temp_dbl2) in large
  515.      * model, where temp_dbl2 is expanded to eliminate all
  516.      * temporary variables, therefore I DO use the temp vars.
  517.      */
  518.  
  519.     double temp_dbl1, temp_dbl2;
  520.  
  521.     temp_dbl1    = (double)pthr->usPolygonSides;
  522.     temp_dbl2    = PI / temp_dbl1;
  523.     dblSideLen   = sin(temp_dbl2);
  524.     dblRotation  = PI - dblAngleDecr;
  525.     dblRotation  = 0.5 * dblRotation + pthr->dblRotation;
  526.     }
  527.  
  528.     {
  529.     double temp_dbl1, temp_dbl2;
  530.  
  531.     temp_dbl1  = (double) pthr->rcl.xRight;
  532.     temp_dbl2  = (double) pthr->cxWCS;
  533.     dblXScale  = temp_dbl1 / temp_dbl2;
  534.     dblXScale *= pthr->dblXScale * dblSideLen;
  535.  
  536.     temp_dbl1  = (double) pthr->rcl.yTop;
  537.     temp_dbl2  = (double) pthr->cyWCS;
  538.     dblYScale  = temp_dbl1 / temp_dbl2;
  539.     dblYScale *= pthr->dblYScale * dblSideLen;
  540.     }
  541.  
  542.     dblXExtDims  = (double) pthr->rcl.xRight * pthr->dblXScale;
  543.     dblYExtDims  = (double) pthr->rcl.yTop   * pthr->dblYScale;
  544.     dblHalfXDims = 0.5 * dblXExtDims;
  545.     dblHalfYDims = 0.5 * dblYExtDims;
  546.     dblXOff     = (double) pthr->rcl.xRight * pthr->dblXOff + dblHalfXDims;
  547.     dblYOff     = (double) pthr->rcl.yTop   * pthr->dblYOff + dblHalfYDims;
  548.  
  549.     dblTheta     = PI + pthr->dblRotation;
  550.  
  551.     for (i = 0; i < pthr->usPolygonSides; ++i)
  552.     {
  553.     dblCosRotation = cos(dblRotation);
  554.     dblSinRotation = sin(dblRotation);
  555.  
  556.     dx = dblHalfXDims * cos(dblTheta);
  557.     dy = dblHalfYDims * sin(dblTheta);
  558.  
  559.     /* 0.000015 = about 1/65536 */
  560.  
  561.     pmatlf = pthr->pmatlf + i;
  562.     pmatlf->fxM11 = (FIXED)(( dblCosRotation * dblXScale + 0.000015) * (double) 0x10000L);
  563.     pmatlf->fxM12 = (FIXED)(( dblSinRotation * dblYScale + 0.000015) * (double) 0x10000L);
  564.     pmatlf-> lM13 = 0L;
  565.     pmatlf->fxM21 = (FIXED)((-dblSinRotation * dblXScale + 0.000015) * (double) 0x10000L);
  566.     pmatlf->fxM22 = (FIXED)(( dblCosRotation * dblYScale + 0.000015) * (double) 0x10000L);
  567.     pmatlf-> lM23 = 0L;
  568.     pmatlf-> lM31 = (LONG) (dblXOff + dx + 0.5);
  569.     pmatlf-> lM32 = (LONG) (dblYOff + dy + 0.5);
  570.     pmatlf-> lM33 = 1L;
  571.  
  572.     dblRotation -= dblAngleDecr;
  573.     dblTheta    -= dblAngleDecr;
  574.     }
  575. }
  576.  
  577.  
  578.  
  579.  
  580. /************************************************************************
  581. *
  582. *   LineFractal
  583. *
  584. *   Draw fractal with the given similarity transform.
  585. *
  586. *   The general idea is to define a transformation to apply to the
  587. *   unit line segment, to get a new polyline.  This same transformation
  588. *   is then applied to each line segment of the new polyline.  The number
  589. *   of successive applications of the similarity transform is set by the
  590. *   user.  It's known as the level of recursion of the fractal.
  591. *
  592. *   Since this is where the point accumulation process will usually
  593. *   be, it recognizes the flag    fInterrupted  to allow the current
  594. *   work to be abandoned.
  595. *
  596. ************************************************************************/
  597.  
  598. VOID
  599. LineFractal(pthr, depth, len, ang, flip, xform)
  600. PTHR pthr;
  601. int depth;
  602. double len;
  603. double ang;
  604. BOOL flip;
  605. PLINEFRAC xform;
  606. {
  607.     double newlen;
  608.     PLINEFRAC newseg;
  609.  
  610.  
  611.     if (pthr->fInterrupted)
  612.     return;
  613.  
  614.     if (depth)
  615.     {
  616.     /*
  617.      *  We have not reached the maximum depth of recursion yet,
  618.      *  so apply the similarity transform to the current line
  619.      *  segment.
  620.      */
  621.  
  622.     --depth;
  623.     newseg = xform;
  624.     do
  625.     {
  626.         newlen  = len * newseg->length;
  627.         ang    += newseg->angle * (flip ? -1 : 1);
  628.         LineFractal(pthr, depth, newlen, ang, (flip ^ newseg->flip), xform);
  629.     } while ((newseg = newseg->next) != EOLIST);
  630.     }
  631.     else
  632.     {
  633.     /*
  634.      *  We have reached the maximum depth of recursion, so
  635.      *  draw a line segment.
  636.      */
  637.  
  638.     pthr->x += len * cos(ang);
  639.     pthr->y += len * sin(ang);
  640.     LfAddPoint(pthr);
  641.     }
  642. }
  643.  
  644.  
  645.  
  646.  
  647. /************************************************************************
  648. *
  649. *   LfAddPoint
  650. *
  651. *   Applies the global coordinate transform to the point (x, y), then
  652. *   stuffs it into the global PolyLine point array, and increments the
  653. *   count of points in the array.
  654. *
  655. ************************************************************************/
  656.  
  657. VOID
  658. LfAddPoint(pthr)
  659. PTHR pthr;
  660. {
  661.     if (pthr->cptl == (ULONG)pthr->cptMax)
  662.     LfDraw(pthr, TRUE);
  663.  
  664.     if (pthr->cptl < (ULONG)pthr->cptMax)
  665.     {
  666.     (pthr->pptl + pthr->cptl)->x =
  667.         (int)(pthr->x + 0.5);
  668.     (pthr->pptl + pthr->cptl)->y =
  669.         (int)(pthr->y + 0.5);
  670.     ++pthr->cptl;
  671.     }
  672. }
  673.  
  674.  
  675.  
  676.  
  677. /************************************************************************
  678. *
  679. *   LfDraw
  680. *
  681. *   For each segment of the frame, set the model transform and draw the
  682. *   cache of points in the current primitive.
  683. *
  684. *   Invalidate the client rectangle of the main window in case this is
  685. *   the top thread, to cause our latest bitmap to be copied there.
  686. *
  687. ************************************************************************/
  688.  
  689. VOID
  690. LfDraw(pthr, fFlush)
  691. PTHR pthr;
  692. BOOL fFlush;
  693. {
  694.     int i;
  695.     BOOL myFlush;
  696.  
  697.  
  698.     /* If this is a direct DC, but is not the top thread, then
  699.      * don't draw anything.
  700.      */
  701.     if (pthr->dcType == IDM_DCDIRECT)
  702.     if (!LfIsThreadTop(pthr))
  703.     {
  704.         if (fFlush)
  705.         pthr->cptl = 0L;
  706.         return;
  707.     }
  708.  
  709.  
  710.     if (pthr->fCollectBounds)
  711.     GpiResetBoundaryData(pthr->hps);
  712.  
  713.  
  714.     myFlush = FALSE;
  715.  
  716.     for (i = 0; i < pthr->usPolygonSides; ++i)
  717.     {
  718.     if (pthr->fInterrupted)
  719.         return;
  720.  
  721.     /* set model transform */
  722.     GpiSetModelTransformMatrix(pthr->hps, 9L, pthr->pmatlf+i, TRANSFORM_REPLACE);
  723.  
  724.     /* we only really flush the last time we use the cache */
  725.     if (i == pthr->usPolygonSides - 1)
  726.         myFlush = fFlush;
  727.  
  728.     switch ( pthr->usCurPrim )
  729.     {
  730.     case IDM_POLYLINE:
  731.         LfDrawPolyLine(pthr, myFlush);
  732.         break;
  733.  
  734.     case IDM_POLYFILLET:
  735.         LfDrawPolyFillet(pthr, myFlush);
  736.         break;
  737.  
  738.     case IDM_POLYSPLINE:
  739.         LfDrawPolySpline(pthr, myFlush);
  740.         break;
  741.  
  742.     case IDM_PEANO:
  743.         LfDrawPolyPeano(pthr, myFlush);
  744.         break;
  745.  
  746.     case IDM_POLYMARKER:
  747.         LfDrawPolyMarker(pthr, myFlush);
  748.         break;
  749.     }
  750.  
  751.     if (pthr->dcType != IDM_DCDIRECT)
  752.         if (LfIsThreadTop(pthr))
  753.         {
  754.         if (pthr->fCollectBounds)
  755.         {
  756.             GpiQueryBoundaryData(pthr->hps, &pthr->rclBounds);
  757.             ++(pthr->rclBounds).xRight;
  758.             ++(pthr->rclBounds).yTop;
  759.             WinInvalidateRect(global.hwnd, &pthr->rclBounds, FALSE);
  760.         }
  761.         else
  762.             WinInvalidateRect(global.hwnd, &pthr->rcl, FALSE);
  763.         }
  764.     }
  765. }
  766.  
  767.  
  768.  
  769.  
  770. /************************************************************************
  771. *
  772. *   LfDrawPolyLine
  773. *
  774. *   Draw a polyline using the thread's point buffer.
  775. *
  776. ************************************************************************/
  777.  
  778. VOID
  779. LfDrawPolyLine(pthr, fFlush)
  780. PTHR pthr;
  781. BOOL fFlush;
  782. {
  783.     /* After drawing the line, save the last point to set the
  784.        current position before the next call. */
  785.  
  786.     GpiSetCurrentPosition( pthr->hps, pthr->pptl );
  787.     GpiPolyLine( pthr->hps, pthr->cptl-1L, pthr->pptl+1 );
  788.     if (fFlush)
  789.     {
  790.     *pthr->pptl = *(pthr->pptl + pthr->cptl-1);
  791.     pthr->cptl = 1L;
  792.     }
  793. }
  794.  
  795.  
  796.  
  797.  
  798. /************************************************************************
  799. *
  800. *   LfDrawPolyFillet
  801. *
  802. *   Draw a polyfillet using the thread's point buffer.
  803. *
  804. ************************************************************************/
  805.  
  806. VOID
  807. LfDrawPolyFillet(pthr, fFlush)
  808. PTHR pthr;
  809. BOOL fFlush;
  810. {
  811.     /* After drawing the curve, save the last point to set the
  812.        current position before the next call. */
  813.  
  814.     if (pthr->cptl > 2)
  815.     {
  816.     GpiSetCurrentPosition( pthr->hps, pthr->pptl );
  817.     GpiPolyFillet( pthr->hps, pthr->cptl-1L, pthr->pptl+1 );
  818.     if (fFlush)
  819.     {
  820.         *pthr->pptl = *(pthr->pptl + pthr->cptl-1);
  821.         pthr->cptl = 1L;
  822.     }
  823.     }
  824. }
  825.  
  826.  
  827.  
  828.  
  829. /************************************************************************
  830. *
  831. *   LfDrawPolySpline
  832. *
  833. *   Draw a polyspline using the thread's point buffer.
  834. *
  835. ************************************************************************/
  836.  
  837. VOID
  838. LfDrawPolySpline(pthr, fFlush)
  839. PTHR pthr;
  840. BOOL fFlush;
  841. {
  842.     int i;        /* loop counter */
  843.     USHORT cptSlack;    /* # points in pptl not usable by PolySpline */
  844.  
  845.     /* GpiPolySpline expects the number of points to be a
  846.        multiple of 3.  If we have a non-multiple of three,
  847.        (excluding the first point, which we've used to set
  848.        the current position), only pass the largest multiple
  849.        of three, saving the rest for the next go-round. */
  850.  
  851.     cptSlack = (int)((pthr->cptl-1L) % 3) + 1;
  852.     GpiSetCurrentPosition( pthr->hps, pthr->pptl );
  853.     GpiPolySpline( pthr->hps, pthr->cptl-cptSlack,
  854.            pthr->pptl+1 );
  855.     if (fFlush)
  856.     {
  857.     for (i = 0; i < cptSlack; ++i)
  858.         *(pthr->pptl + i) = *(pthr->pptl + pthr->cptl-cptSlack+i);
  859.     pthr->cptl = cptSlack;
  860.     }
  861. }
  862.  
  863.  
  864.  
  865.  
  866. /************************************************************************
  867. *
  868. *   LfDrawPolyPeano
  869. *
  870. *   Draw a chain of Peano primitives using the thread's point buffer.
  871. *
  872. ************************************************************************/
  873.  
  874. VOID
  875. LfDrawPolyPeano(pthr, fFlush)
  876. PTHR pthr;
  877. BOOL fFlush;
  878. {
  879.     LONG a, b, c, d;    /* temporary vars for Peano curvelet calculations */
  880.     int cptPeano;    /* current point in pptl in use by Peano curve */
  881.     POINTL ptPeano[2];    /* Peano curvelet array to pass to PolyLine */
  882.  
  883.     for (cptPeano = 0; cptPeano < (int)(pthr->cptl-1L); ++cptPeano)
  884.     {
  885.     ptPeano[0] = *(pthr->pptl + cptPeano);
  886.     ptPeano[1] = *(pthr->pptl + cptPeano+1);
  887.     a = (pthr->pptl + cptPeano+1)->x - (pthr->pptl + cptPeano)->x;
  888.     b = (pthr->pptl + cptPeano+1)->y - (pthr->pptl + cptPeano)->y;
  889.     c = (a + b)/2;
  890.     d = (a - b)/2;
  891.     if (labs(a) > labs(b))
  892.     {
  893.         ptPeano[0].x +=  d;
  894.         ptPeano[0].y +=  c;
  895.     }
  896.     else
  897.     {
  898.         ptPeano[0].x +=  c;
  899.         ptPeano[0].y += -d;
  900.     }
  901.  
  902.     GpiSetCurrentPosition( pthr->hps, pthr->pptl + cptPeano);
  903.     GpiPolyLine( pthr->hps, 2L, (PPOINTL)ptPeano);
  904.     }
  905.     if (fFlush)
  906.     {
  907.     *pthr->pptl = *(pthr->pptl + pthr->cptl-1);
  908.     pthr->cptl = 1L;
  909.     }
  910. }
  911.  
  912.  
  913.  
  914.  
  915. /************************************************************************
  916. *
  917. *   LfDrawPolyMarker
  918. *
  919. *   Draw a list of markers using the thread's point buffer.
  920. *
  921. ************************************************************************/
  922.  
  923. VOID
  924. LfDrawPolyMarker(pthr, fFlush)
  925. PTHR pthr;
  926. BOOL fFlush;
  927. {
  928.     /* I want to draw markers at every point in the array, but
  929.        GpiPolyMarker won't draw at the last point!  So, GpiMarker
  930.        does the job instead. */
  931.  
  932.     GpiSetCurrentPosition( pthr->hps, pthr->pptl + pthr->cptl-1);
  933.     GpiPolyMarker( pthr->hps, pthr->cptl, pthr->pptl );
  934.     GpiMarker     ( pthr->hps,          pthr->pptl + pthr->cptl-1 );
  935.  
  936.     if (fFlush)
  937.     pthr->cptl = 0L;
  938. }
  939.  
  940.  
  941.  
  942.  
  943. /************************************************************************
  944. *
  945. *   LfClearRect
  946. *
  947. *   Set the area attributes if needed and fill the bitmap with them.
  948. *
  949. ************************************************************************/
  950.  
  951. VOID
  952. LfClearRect(pthr, prcl)
  953. PTHR pthr;
  954. PRECTL prcl;
  955. {
  956.     PRECTL prclT;
  957.  
  958.     if (pthr->hps)
  959.     {
  960.     if (prcl)
  961.         prclT = prcl;
  962.     else
  963.         prclT = &pthr->rcl;
  964.  
  965.     if (pthr->dcType == IDM_DCDIRECT)
  966.     {
  967.         /* If direct DC, only blt if top thread. */
  968.         if (LfIsThreadTop(pthr))
  969.         GpiBitBlt(pthr->hps, NULL, 2L, (PPOINTL)prclT, ROP_PATCOPY, NULL);
  970.     }
  971.     else
  972.     {
  973.         GpiBitBlt(pthr->hps, NULL, 2L, (PPOINTL)prclT, ROP_PATCOPY, NULL);
  974.         if (LfIsThreadTop(pthr))
  975.         WinInvalidateRect(global.hwnd, prclT, FALSE);
  976.     }
  977.     }
  978. }
  979.